"""
热成像分析系统服务层
包含各种专门的服务类，遵循单一职责原则
"""

import os
import cv2
import numpy as np
from typing import List, Dict, Any, Optional, Tuple, Callable
from dataclasses import dataclass
from abc import ABC, abstractmethod

from ..core.temperature_mapper import TemperatureMapper
from ..core.data_storage import DataStorage
from ..core.video_stream import VideoStreamManager, validate_stream_url


# ========== 数据模型 ==========

@dataclass
class CalibrationPoint:
    """标定点数据模型"""
    position: Tuple[int, int]
    hsv_color: List[float]
    temperature: float
    index: int


@dataclass
class TemperatureResult:
    """温度分析结果数据模型"""
    min_temp: float
    max_temp: float
    avg_temp: float
    min_pos: Tuple[int, int]
    max_pos: Tuple[int, int]
    temp_diff: float
    pixel_count: int = 0


@dataclass
class RegionResult:
    """区域分析结果数据模型"""
    region_id: int
    coordinates: Dict[str, int]
    size: Dict[str, int]
    temperature_result: TemperatureResult


# ========== 基础服务接口 ==========

class BaseService(ABC):
    """服务基类，定义通用接口"""
    
    def __init__(self):
        self._initialized = False
        
    @abstractmethod
    def initialize(self) -> bool:
        """初始化服务"""
        pass
        
    @abstractmethod
    def cleanup(self):
        """清理资源"""
        pass
        
    def is_initialized(self) -> bool:
        """检查服务是否已初始化"""
        return self._initialized


# ========== 图像服务 ==========

class ImageService(BaseService):
    """图像处理服务"""
    
    def __init__(self):
        super().__init__()
        self.current_image = None
        self.current_image_hsv = None
        self.image_source = "unknown"
        
    def initialize(self) -> bool:
        """初始化图像服务"""
        self._initialized = True
        return True
        
    def cleanup(self):
        """清理图像数据"""
        self.current_image = None
        self.current_image_hsv = None
        self.image_source = "unknown"
        
    def load_from_file(self, file_path: str) -> bool:
        """从文件加载图像"""
        try:
            with open(file_path, 'rb') as f:
                image_data = f.read()
            nparr = np.frombuffer(image_data, np.uint8)
            image = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
            
            if image is not None:
                self.current_image = image
                self.current_image_hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
                self.image_source = f"file:{os.path.basename(file_path)}"
                return True
            return False
        except Exception:
            return False
            
    def update_from_stream(self, frame_bgr: np.ndarray, stream_url: str):
        """从视频流更新图像"""
        self.current_image = frame_bgr
        self.current_image_hsv = cv2.cvtColor(frame_bgr, cv2.COLOR_BGR2HSV)
        self.image_source = f"stream:{stream_url}"
        
    def has_image(self) -> bool:
        """检查是否有图像"""
        return self.current_image is not None
        
    def get_image_info(self) -> Dict[str, Any]:
        """获取图像信息"""
        if not self.has_image():
            return {}
            
        height, width = self.current_image.shape[:2]
        return {
            'width': width,
            'height': height,
            'source': self.image_source,
            'channels': self.current_image.shape[2] if len(self.current_image.shape) > 2 else 1
        }
        
    def get_pixel_info(self, x: int, y: int) -> Optional[Dict[str, Any]]:
        """获取指定像素的信息"""
        if not self.has_image():
            return None
            
        try:
            height, width = self.current_image.shape[:2]
            if x >= width or y >= height or x < 0 or y < 0:
                return None
                
            hsv_color = self.current_image_hsv[y, x]
            bgr_color = self.current_image[y, x]
            rgb_color = (int(bgr_color[2]), int(bgr_color[1]), int(bgr_color[0]))
            
            return {
                'position': (x, y),
                'hsv': [int(hsv_color[0]), int(hsv_color[1]), int(hsv_color[2])],
                'rgb': rgb_color,
                'bgr': [int(bgr_color[0]), int(bgr_color[1]), int(bgr_color[2])]
            }
        except (IndexError, ValueError):
            return None


# ========== 标定服务 ==========

class CalibrationService(BaseService):
    """温度标定服务"""
    
    def __init__(self, temp_mapper: TemperatureMapper, data_storage: DataStorage):
        super().__init__()
        self.temp_mapper = temp_mapper
        self.data_storage = data_storage
        self.calibration_mode = False
        
    def initialize(self) -> bool:
        """初始化标定服务"""
        self._initialized = True
        return True
        
    def cleanup(self):
        """清理标定服务"""
        self.calibration_mode = False
        
    def set_calibration_mode(self, enabled: bool):
        """设置标定模式"""
        self.calibration_mode = enabled
        
    def is_calibration_mode(self) -> bool:
        """检查是否处于标定模式"""
        return self.calibration_mode
        
    def add_point(self, x: int, y: int, temperature: float, hsv_color: List[float]) -> bool:
        """添加标定点"""
        try:
            self.temp_mapper.add_calibration_point(hsv_color, temperature, (x, y))
            self.auto_save()
            return True
        except Exception:
            return False
            
    def get_points(self) -> List[CalibrationPoint]:
        """获取所有标定点"""
        calibration_info = self.temp_mapper.get_calibration_info()
        points = []
        
        for i, point_info in enumerate(calibration_info):
            point = CalibrationPoint(
                position=point_info['position'],
                hsv_color=point_info['hsv'],
                temperature=point_info['temperature'],
                index=i
            )
            points.append(point)
            
        return points
        
    def delete_point(self, index: int) -> bool:
        """删除指定索引的标定点"""
        calibration_points = self.temp_mapper.calibration_points.copy()
        calibration_points_with_pos = self.temp_mapper.calibration_points_with_pos.copy()
        
        if 0 <= index < len(calibration_points_with_pos):
            del calibration_points[index]
            del calibration_points_with_pos[index]
            
            self.temp_mapper.calibration_points = calibration_points
            self.temp_mapper.calibration_points_with_pos = calibration_points_with_pos
            
            self.auto_save()
            return True
        return False
        
    def clear_points(self):
        """清空所有标定点"""
        self.temp_mapper.clear_calibration_points()
        
    def auto_save(self) -> Optional[str]:
        """自动保存标定数据"""
        try:
            calibration_points = self.temp_mapper.get_calibration_info()
            if calibration_points:
                return self.data_storage.save_calibration_data(calibration_points)
            return None
        except Exception:
            return None


# ========== 温度分析服务 ==========

class TemperatureAnalysisService(BaseService):
    """温度分析服务"""
    
    def __init__(self, temp_mapper: TemperatureMapper, image_service: ImageService, data_storage: DataStorage):
        super().__init__()
        self.temp_mapper = temp_mapper
        self.image_service = image_service
        self.data_storage = data_storage
        
    def initialize(self) -> bool:
        """初始化分析服务"""
        self._initialized = True
        return True
        
    def cleanup(self):
        """清理分析服务"""
        pass
        
    def get_pixel_temperature(self, x: int, y: int) -> Optional[Dict[str, Any]]:
        """获取指定像素的温度信息"""
        pixel_info = self.image_service.get_pixel_info(x, y)
        if pixel_info is None:
            return None
            
        try:
            hsv_color = pixel_info['hsv']
            temperature = self.temp_mapper.color_to_temperature(hsv_color)
            
            result = pixel_info.copy()
            result['temperature'] = float(temperature)
            return result
        except Exception:
            return None
            
    def analyze_global(self) -> Optional[TemperatureResult]:
        """全局温度分析"""
        if not self.image_service.has_image():
            return None
            
        try:
            height, width = self.image_service.current_image_hsv.shape[:2]
            temp_map = np.zeros((height, width), dtype=np.float32)
            
            for y in range(height):
                for x in range(width):
                    hsv_color = self.image_service.current_image_hsv[y, x]
                    temp_map[y, x] = self.temp_mapper.color_to_temperature(hsv_color)
                    
            min_temp = float(np.min(temp_map))
            max_temp = float(np.max(temp_map))
            avg_temp = float(np.mean(temp_map))
            min_pos = np.unravel_index(np.argmin(temp_map), temp_map.shape)
            max_pos = np.unravel_index(np.argmax(temp_map), temp_map.shape)
            
            result = TemperatureResult(
                min_temp=min_temp,
                max_temp=max_temp,
                avg_temp=avg_temp,
                min_pos=(int(min_pos[1]), int(min_pos[0])),
                max_pos=(int(max_pos[1]), int(max_pos[0])),
                temp_diff=max_temp - min_temp,
                pixel_count=height * width
            )
            
            # 不再自动保存全局分析结果
            return result
            
        except Exception:
            return None
            
    def analyze_regions(self, regions: List[Dict[str, int]]) -> List[RegionResult]:
        """区域温度分析"""
        if not self.image_service.has_image():
            return []
            
        results = []
        
        for i, region_data in enumerate(regions):
            try:
                x1, y1 = region_data['x1'], region_data['y1'] 
                x2, y2 = region_data['x2'], region_data['y2']
                
                area_temps = []
                for y in range(y1, y2):
                    for x in range(x1, x2):
                        hsv_shape = self.image_service.current_image_hsv.shape
                        if 0 <= x < hsv_shape[1] and 0 <= y < hsv_shape[0]:
                            hsv_color = self.image_service.current_image_hsv[y, x]
                            temp = self.temp_mapper.color_to_temperature(hsv_color)
                            area_temps.append((temp, x, y))
                            
                if area_temps:
                    area_temps.sort(key=lambda item: item[0])
                    
                    min_temp_data = area_temps[0]
                    max_temp_data = area_temps[-1]
                    
                    temperature_result = TemperatureResult(
                        min_temp=min_temp_data[0],
                        max_temp=max_temp_data[0],
                        avg_temp=sum(item[0] for item in area_temps) / len(area_temps),
                        min_pos=(min_temp_data[1], min_temp_data[2]),
                        max_pos=(max_temp_data[1], max_temp_data[2]),
                        temp_diff=max_temp_data[0] - min_temp_data[0],
                        pixel_count=len(area_temps)
                    )
                    
                    region_result = RegionResult(
                        region_id=i + 1,
                        coordinates={'x1': x1, 'y1': y1, 'x2': x2, 'y2': y2},
                        size={'width': x2 - x1, 'height': y2 - y1},
                        temperature_result=temperature_result
                    )
                    
                    results.append(region_result)
                    
            except (KeyError, ValueError, IndexError):
                continue
                
        # 不再自动保存区域分析结果
        return results
        
    def analyze_realtime(self) -> Optional[TemperatureResult]:
        """实时温度分析（采样模式，提高性能）"""
        if not self.image_service.has_image():
            return None
            
        try:
            height, width = self.image_service.current_image_hsv.shape[:2]
            sample_step = max(1, min(height, width) // 50)
            temp_samples = []
            
            for y in range(0, height, sample_step):
                for x in range(0, width, sample_step):
                    hsv_color = self.image_service.current_image_hsv[y, x]
                    temp = self.temp_mapper.color_to_temperature(hsv_color)
                    temp_samples.append((temp, x, y))
                    
            if temp_samples:
                temp_samples.sort(key=lambda item: item[0])
                
                min_data = temp_samples[0]
                max_data = temp_samples[-1]
                avg_temp = sum(item[0] for item in temp_samples) / len(temp_samples)
                
                return TemperatureResult(
                    min_temp=min_data[0],
                    max_temp=max_data[0],
                    avg_temp=avg_temp,
                    min_pos=(min_data[1], min_data[2]),
                    max_pos=(max_data[1], max_data[2]),
                    temp_diff=max_data[0] - min_data[0],
                    pixel_count=len(temp_samples)
                )
                
        except Exception:
            pass
            
        return None
        
    def _save_global_result(self, result: TemperatureResult) -> Optional[str]:
        """保存全局分析结果"""
        try:
            image_info = self.image_service.get_image_info()
            save_data = {
                'image_info': image_info,
                'global_stats': {
                    'min_temp': result.min_temp,
                    'max_temp': result.max_temp,
                    'avg_temp': result.avg_temp,
                    'min_pos': result.min_pos,
                    'max_pos': result.max_pos,
                    'temp_diff': result.temp_diff
                },
                'regions': []
            }
            return self.data_storage.save_analysis_result(save_data)
        except Exception:
            return None
            
    def _save_regions_result(self, results: List[RegionResult]) -> Optional[str]:
        """保存区域分析结果"""
        try:
            image_info = self.image_service.get_image_info()
            save_data = {
                'image_info': image_info,
                'regions': []
            }
            
            for region in results:
                region_data = {
                    'x1': region.coordinates['x1'],
                    'y1': region.coordinates['y1'],
                    'x2': region.coordinates['x2'],
                    'y2': region.coordinates['y2'],
                    'width': region.size['width'],
                    'height': region.size['height'],
                    'stats': {
                        'min_temp': region.temperature_result.min_temp,
                        'max_temp': region.temperature_result.max_temp,
                        'avg_temp': region.temperature_result.avg_temp,
                        'temp_diff': region.temperature_result.temp_diff,
                        'min_pos': region.temperature_result.min_pos,
                        'max_pos': region.temperature_result.max_pos,
                        'pixel_count': region.temperature_result.pixel_count
                    }
                }
                save_data['regions'].append(region_data)
                
            return self.data_storage.save_analysis_result(save_data)
        except Exception:
            return None


# ========== 视频流服务 ==========

class StreamService(BaseService):
    """视频流服务"""
    
    def __init__(self, image_service: ImageService):
        super().__init__()
        self.image_service = image_service
        self.stream_manager = VideoStreamManager()
        self.is_streaming = False
        self.current_stream_url = None
        self.stream_callbacks: List[Callable] = []
        
    def initialize(self) -> bool:
        """初始化流服务"""
        self._initialized = True
        return True
        
    def cleanup(self):
        """清理流服务"""
        if self.is_streaming:
            self.stop_stream()
        self.stream_callbacks.clear()
        
    def add_callback(self, callback: Callable[[np.ndarray, np.ndarray], None]):
        """添加流帧回调"""
        self.stream_callbacks.append(callback)
        
    def remove_callback(self, callback: Callable):
        """移除流帧回调"""
        if callback in self.stream_callbacks:
            self.stream_callbacks.remove(callback)
            
    def start_stream(self, stream_url: str, fps_limit: int = 10, frame_skip: int = 1) -> bool:
        """启动视频流"""
        is_valid, _ = validate_stream_url(stream_url)
        if not is_valid:
            return False
            
        def frame_callback(frame_bgr, frame_hsv):
            # 更新图像服务
            self.image_service.update_from_stream(frame_bgr, stream_url)
            
            # 触发用户回调
            for callback in self.stream_callbacks:
                try:
                    callback(frame_bgr, frame_hsv)
                except Exception:
                    pass
                    
        self.stream_manager.add_frame_callback(frame_callback)
        
        if self.stream_manager.start_stream(stream_url, fps_limit, frame_skip):
            self.is_streaming = True
            self.current_stream_url = stream_url
            return True
        return False
        
    def stop_stream(self) -> bool:
        """停止视频流"""
        try:
            self.stream_manager.stop_stream()
            self.is_streaming = False
            self.current_stream_url = None
            return True
        except Exception:
            return False
            
    def get_status(self) -> Dict[str, Any]:
        """获取流状态"""
        return {
            'is_streaming': self.is_streaming,
            'stream_url': self.current_stream_url,
            'callback_count': len(self.stream_callbacks)
        }


# ========== 服务管理器 ==========

class ServiceManager:
    """服务管理器，统一管理所有服务实例"""
    
    def __init__(self):
        # 初始化核心组件
        self.temp_mapper = TemperatureMapper()
        self.data_storage = DataStorage()
        
        # 初始化服务实例
        self.image_service = ImageService()
        self.calibration_service = CalibrationService(self.temp_mapper, self.data_storage)
        self.temperature_service = TemperatureAnalysisService(
            self.temp_mapper, self.image_service, self.data_storage
        )
        self.stream_service = StreamService(self.image_service)
        
        self._initialized = False
        
    def initialize(self) -> bool:
        """初始化所有服务"""
        services = [
            self.image_service,
            self.calibration_service, 
            self.temperature_service,
            self.stream_service
        ]
        
        for service in services:
            if not service.initialize():
                return False
                
        self._initialized = True
        return True
        
    def cleanup(self):
        """清理所有服务"""
        services = [
            self.stream_service,
            self.temperature_service,
            self.calibration_service,
            self.image_service
        ]
        
        for service in services:
            try:
                service.cleanup()
            except Exception:
                pass
                
        self._initialized = False
        
    def is_initialized(self) -> bool:
        """检查服务管理器是否已初始化"""
        return self._initialized
        
    # 便捷访问方法
    @property
    def image(self) -> ImageService:
        return self.image_service
        
    @property
    def calibration(self) -> CalibrationService:
        return self.calibration_service
        
    @property
    def temperature(self) -> TemperatureAnalysisService:
        return self.temperature_service
        
    @property
    def stream(self) -> StreamService:
        return self.stream_service